#include "Screen.h"
SDL_Surface *Screen::m_pSurface;
Mutex Screen::m_lockSurface;

void Screen::ShowImage(const Image *pImage)
{
	ScopeLocker<Mutex> l(&m_lockSurface);
	SDL_LockSurface(m_pSurface);
	S32 nRow, nCol;
	U8 *pDest = (U8*)m_pSurface->pixels;
	U8 *pSrc = (U8*)pImage->GetData();
	S32 nViewWidth, nViewHeight;	
	Rect<S32> screenRect;
	
	GetImageOrViewDrawRect(pImage, &screenRect);
	nViewWidth = screenRect.Width();
	nViewHeight = screenRect.Height();	
	pDest += (screenRect.Left() + screenRect.Top() * m_pSurface->w) * 4;
	for(nRow = 0; nRow < nViewHeight; ++nRow) {
		for(nCol = 0; nCol < nViewWidth; ++nCol) {
			U8 pix = *pSrc; pSrc++;
			*pDest++ = pix;
			*pDest++ = pix;
			*pDest++ = pix;
			pDest++;
		}
		pDest += (m_pSurface->w - nViewWidth) * 4;
	}
	SDL_UnlockSurface(m_pSurface);
	SDL_UpdateRect(m_pSurface, screenRect.Left(), screenRect.Top(), screenRect.Width(), screenRect.Height());
	
}

void Screen::ShowView(const View *pView)
{
	ScopeLocker<Mutex> l(&m_lockSurface);
	SDL_LockSurface(m_pSurface);
	U8 *p = (U8*)m_pSurface->pixels;
	S32 nViewWidth, nViewHeight;
	Rect<S32> screenRect;
	Rect<S32> viewRect;
	pView->GetBoundingRect(&viewRect);
	GetImageOrViewDrawRect(pView, &screenRect);
	nViewWidth = screenRect.Width();
	nViewHeight = screenRect.Height();	
	p += (screenRect.Left() + screenRect.Top() * m_pSurface->w) * 4;
	pView->OutputPixels(p, m_pSurface->w - nViewWidth, true);
	SDL_UnlockSurface(m_pSurface);
	SDL_UpdateRect(m_pSurface, screenRect.Left(), screenRect.Top(), screenRect.Width(), screenRect.Height());
}

void Screen::DrawRect(Rect<S32> *pRect, U8 nRed, U8 nGreen, U8 nBlue)
{
	S32 nLeft, nRight, nTop, nBottom;
	nLeft = pRect->Left() < 0 ? 0 : pRect->Left();
	nTop = pRect->Top() < 0 ? 0 : pRect->Top();
	nRight = pRect->Right() >= m_pSurface->w ? (m_pSurface->w - 1) : pRect->Right();
	nBottom = pRect->Bottom() >= m_pSurface->h ? (m_pSurface->h - 1) : pRect->Bottom();
	
	ScopeLocker<Mutex> l(&m_lockSurface);
	SDL_LockSurface(m_pSurface);
	DrawRectNoSync(pRect, nRed, nGreen, nBlue);
	SDL_UnlockSurface(m_pSurface);
	SDL_UpdateRect(m_pSurface, nLeft, nTop, nRight - nLeft + 1, nBottom - nTop + 1);
}

void Screen::DrawRectNoSync(Rect<S32> *pRect, U8 nRed, U8 nGreen, U8 nBlue)
{	
	S32 nLeft, nRight, nTop, nBottom;
	S32 nRow, nCol;
	nLeft = pRect->Left() < 0 ? 0 : pRect->Left();
	nTop = pRect->Top() < 0 ? 0 : pRect->Top();
	nRight = pRect->Right() >= m_pSurface->w ? (m_pSurface->w - 1) : pRect->Right();
	nBottom = pRect->Bottom() >= m_pSurface->h ? (m_pSurface->h - 1) : pRect->Bottom();
	
	nRight = nRight < nLeft ? nLeft : nRight;
	nBottom = nBottom < nTop ? nTop : nBottom;
	
	U8 *p = (U8*)m_pSurface->pixels + (nTop * m_pSurface->w + nLeft) * 4;
	for(nRow = nTop; nRow <= nBottom; ++nRow) {
		for(nCol = nLeft; nCol <= nRight; ++nCol) {
			*p++ = nBlue;
			*p++ = nGreen;
			*p++ = nRed;
			p++;
		}
		p += (m_pSurface->w - (nRight - nLeft + 1)) * 4;
	}
}

void Screen::DrawPointVector(std::vector < Point <S32> > * pVec, U8 nRed, U8 nGreen, U8 nBlue, 
                             S32 nThickness)
{
	ScopeLocker<Mutex> l(&m_lockSurface);
	SDL_LockSurface(m_pSurface);
	std::vector< Point <S32> >::iterator iter;
	for(iter = pVec->begin(); iter != pVec->end(); ++iter) {
		Rect <S32> r;
		r.SetCenterWidthHeight(*iter, nThickness, nThickness); 
		DrawRectNoSync(&r, nRed, nGreen, nBlue);
	}
	SDL_UnlockSurface(m_pSurface);
	SDL_UpdateRect(m_pSurface, 0, 0, m_pSurface->w, m_pSurface->h);
}

void Screen::Init()
{
	ScopeLocker<Mutex> l(&m_lockSurface);
	m_pSurface = SDL_SetVideoMode(1024, 768, 32, SDL_HWSURFACE);
}

bool Screen::IsReady()
{
	ScopeLocker<Mutex> l(&m_lockSurface);
	return (bool)m_pSurface;
}


